#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h> 
#include <stdlib.h>       
#include <string.h>
#include <pthread.h>
//#include <sys/sem.h>
#include <errno.h>
#include <sys/ipc.h>
//#include <sys/msg.h>
#include <sys/timeb.h>
#include <sys/socket.h>
//#include <sys/socketvar.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <semaphore.h>
#include <linux/shm.h>
#include <sys/poll.h>
#include <sys/epoll.h>

#include "common.h"

static struct audioSource *pComposedAudioSource = NULL;

static int aac_frequency[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,8000,8000,8000,8000,8000,8000};

extern SystemParam* pgSystemParam;

struct audioSource *GetComposedAudioSource()
{
		return pComposedAudioSource;
}

int initComposedAudioSource()
{
		if( InitAudioSource(&pComposedAudioSource) != 0 )
			return -1;
			
		InitAudio(&pComposedAudioSource);
			
		return 0;
}


int InitAudioSource(struct audioSource **pAudioSource)
{
		if( ( *pAudioSource = (struct audioSource *)malloc(sizeof(struct audioSource)) ) == NULL )	
		{
				return -1;	
		}	
		
		memset(*pAudioSource,0x0,sizeof(struct audioSource));
	
		if( pthread_mutex_init (&((*pAudioSource)->Lock),NULL) != 0   ) 
		{
				printf("pthread_mutex_init failure {%s(%d)}\n",__FILE__,__LINE__);	
				return -1;
		}	
		
		return 0;	
}

int InitAudio(struct audioSource **pAudioSource)
{
		if(pAudioSource == NULL)
		{
				printf("pAudioSource is null ! {%s(%d)} \n", __FILE__, __LINE__);	
				return -1;	
		}
		
		return realInitAudio(*pAudioSource);
}

static int realInitAudio(struct audioSource *pAudioSource)
{
		pthread_t ptID;	
		size_t stacksize;
		pthread_attr_t attr;
		
		if( pthread_attr_init(&attr) != 0 )
			  printf("pthread_attr_init failure {%s(%d)}\n",__FILE__,__LINE__);	  
		if( pthread_attr_getstacksize (&attr, &stacksize) != 0 )
				printf("pthread_attr_getstacksize failure {%s(%d)}\n",__FILE__,__LINE__);	  	  
		if( pthread_attr_setstacksize (&attr, 64*1024) != 0 )
			  printf("pthread_attr_getstacksize failure {%s(%d)}\n",__FILE__,__LINE__);	
			  
		if( pthread_create(&ptID, &attr,handleAudioDataThread, (void *)pAudioSource) != 0 )
		{
				printf("pthread_create Init Failed\n");
				return -1;
		}					  		
		
		return 0;
}

static void* handleAudioDataThread(void* arg)
{
		struct audioSource* pAudioSource = (struct audioSource*)arg;
		
		unsigned int timestamp=0;
		struct timespec ts;
		struct timeval  tv;			
		
		while( !IsExit() ) 
		{
				gettimeofday(&tv, NULL); 
				
			  ts.tv_sec  = tv.tv_sec + 2;
		    ts.tv_nsec = tv.tv_usec * 1000;		
		    
		    sem_timedwait(&(pgSystemParam->aacAudioBlock.m_Semaphore),&ts);		    	
		    
		 		while( pgSystemParam->aacAudioBlock.m_Pop->nFlag )
				{						
						AudioData(pAudioSource, pgSystemParam->aacAudioBlock.m_Pop->pData,pgSystemParam->aacAudioBlock.m_Pop->nSize,timestamp);
						
						pthread_mutex_lock (&(pgSystemParam->aacAudioBlock.m_Lock));
		 				pgSystemParam->aacAudioBlock.m_Pop->nFlag = 0;
						pgSystemParam->aacAudioBlock.m_Pop = pgSystemParam->aacAudioBlock.m_Pop->pNext;
						pthread_mutex_unlock (&(pgSystemParam->aacAudioBlock.m_Lock));
				}
					
		}
		
		return NULL;
}

static void  AudioData(struct audioSource* pAudioSource, unsigned char *pData,int iSize,unsigned int & timestamp)
{
		int ret;
		
		static PictureInfo *pTmpPictureInfo;
		
		char pBuf[80];
	
		//if( iSize < int( 7 + sizeof(PictureInfo) ) ) return;		
		//unsigned char *pTemp = pData + sizeof(PictureInfo);
		
		if( iSize < int( 7 ) ) return;		
		unsigned char *pTemp = pData;
		
		if(pAudioSource == NULL) return;
		
		pthread_mutex_lock (&(pAudioSource->Lock));
		pAudioSource->iAudioObjectType	             = (0x0003&(pTemp[2]>>6) ) + 1;
		pAudioSource->iAudioSamplingFrequencyIndex	 =  0x000F&(pTemp[2]>>2);
		pAudioSource->iAudioChannelConfiguration	   = (0x0004&(pTemp[2]<<2))|(0x0003&(pTemp[3]>>6));
		memcpy(pAudioSource->data, pData, iSize);
		pAudioSource->dataSize = iSize;
		pthread_mutex_unlock (&(pAudioSource->Lock));	
		
		//printf("iAudioObjectType,iAudioSamplingFrequencyIndex,iAudioChannelConfiguration = %d,%d,%d\n",
		//			pAudioSource->iAudioObjectType, pAudioSource->iAudioSamplingFrequencyIndex, pAudioSource->iAudioChannelConfiguration);
		
		pTmpPictureInfo = (PictureInfo *)pData;
		pTmpPictureInfo->w      = pAudioSource->iAudioSamplingFrequencyIndex;
		pTmpPictureInfo->h      = pAudioSource->iAudioChannelConfiguration;
		pTmpPictureInfo->mode   = STREAM_MODE_AUDIO;
		pTmpPictureInfo->stream = pAudioSource->iAudioObjectType;	
		pTmpPictureInfo->off    = 0;
		pTmpPictureInfo->timestamp = timestamp;
		timestamp += 1024*1000/GetSamplingRate(pAudioSource->iAudioSamplingFrequencyIndex);		
		
	  if( (ret = PushBlockInfoData(&(pgSystemParam->TeacherSave),pData,iSize, (unsigned char *)pTmpPictureInfo, sizeof(PictureInfo))) != 0 )
		{
				printf("M:%d {%s(%d)}\n",ret,__FILE__,__LINE__);
				sprintf(pBuf,"M:%d",ret);
				WriteLog(pBuf,__FILE__,__LINE__);
		}					
		
		if( (ret = PushBlockInfoData(&(pgSystemParam->StudentSave),pData,iSize, (unsigned char *)pTmpPictureInfo, sizeof(PictureInfo))) != 0 )
		{
				printf("M:%d {%s(%d)}\n",ret,__FILE__,__LINE__);
				sprintf(pBuf,"M:%d",ret);
				WriteLog(pBuf,__FILE__,__LINE__);
		}		
}

int GetSamplingRate(int index)
{
		if( ( index < 0 ) || ( index >= 16 ) )	return -1;
		return aac_frequency[index];
}

